import React, { createContext, useContext } from 'react';

type SlotMap = Map<string, React.ReactNode>;

interface SlotContextType {
  slots: SlotMap;
  addSlot: (name: string, content: React.ReactNode) => void;
  scope: any;
}

const SlotContext = createContext<SlotContextType>({
  slots: new Map(),
  addSlot: () => {},
  scope: null,
});

export const useSlot = (name: string, defaultValue?: React.ReactNode) => {
  const { slots, scope } = useContext(SlotContext);
  return slots.get(`${scope}.${name}`) ?? defaultValue;
};

interface SlotProps {
  name?: string;
  children?: React.ReactNode;
}

export const Slot: React.FC<SlotProps> = ({ name, children }) => {
  const { addSlot, scope } = useContext(SlotContext);
  addSlot(`${scope}.${name || ''}`, children);
  return null;
};

interface SlotProviderProps {
  children: React.ReactNode;
  scope?: any;
}

export const SlotProvider: React.FC<SlotProviderProps> = ({
  children,
  scope,
}) => {
  const [slots, setSlots] = React.useState(new Map());

  const addSlot = React.useCallback(
    (name: string, content: React.ReactNode) => {
      setSlots((prevSlots) => new Map(prevSlots).set(name, content));
    },
    [],
  );

  const memoizedSlots = React.useMemo(() => new Map(slots), [slots]);

  const value = React.useMemo(
    () => ({ slots: memoizedSlots, addSlot, scope }),
    [memoizedSlots, addSlot, scope],
  );

  return <SlotContext.Provider value={value}>{children}</SlotContext.Provider>;
};
